﻿using System.Windows;
using System.Windows.Controls;
using DeepEarth.Core;
using DeepEarth.Core.Utilities;
using DeepEarth.Map.Core.Utilities;
namespace DeepEarth.Map.Core
{
    public abstract class BaseLayer : Canvas
    {
        public BaseLayer()
        {
            this.LayoutUpdated += BaseLayer_LayoutUpdated;
            this.SizeChanged += BaseLayer_SizeChanged;
        }

        void BaseLayer_LayoutUpdated(object sender, System.EventArgs e)
        {
            if (MapInstance != null)
            {
                this.LayoutUpdated -= BaseLayer_LayoutUpdated;
            }
        }

        void BaseLayer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            SynchronizeOffsets();
        }


        IMap map;
        public IMap MapInstance
        {
            get
            {
                if (map == null)
                {
                    map = Utilities.VisualTree.FindAncestor<IMap>(this);

                    if (map != null)
                    {
                        var weakChangeOnFrame = new WeakEventListener<BaseLayer, IMap>(this, map)
                        {
                            DetatchAction = (listener, source) => { source.ViewChangeOnFrame -= listener.OnEvent; },
                            EventAction = (self, sender, args) => { self.SynchronizeOnFrame(); }
                        };
                        map.ViewChangeOnFrame += weakChangeOnFrame.OnEvent;

                        var weakChengeEnd = new WeakEventListener<BaseLayer, IMap>(this, map)
                        {
                            DetatchAction = (listener, source) => { source.ViewChangeEnd -= listener.OnEvent; },
                            EventAction = (self, sender, args) => { self.SynchronizeOnEnd(); }
                        };
                        map.ViewChangeEnd += weakChengeEnd.OnEvent;

                        MapChanged();
                    }
                }
                return map;
            }
        }

        protected virtual void MapChanged()
        {
        }

        protected abstract void SynchronizeOnFrame();

        protected abstract void SynchronizeOnEnd();

        public virtual void Refresh()
        {
            SynchronizeOnFrame();
        }

        #region Custom LocationToViewportPoint

        double OffsetX { get; set; }
        double OffsetY { get; set; }
        protected double GlobalMapPixelWidth { get; set; }
        protected double MapLogicalWidth { get; set; }
        double MapViewportPixelWidth { get; set; }
        double MapViewportPixelHeight { get; set; }
        Point ZoomedOutYOffset { get; set; }

        public void SynchronizeOffsets()
        {
            MapLogicalWidth = MapInstance.CurrentViewportLogicalWidth;

            MapViewportPixelWidth = MapInstance.AsFrameworkElement.ActualWidth;
            MapViewportPixelHeight = MapInstance.AsFrameworkElement.ActualHeight;
            GlobalMapPixelWidth = MapViewportPixelWidth / MapLogicalWidth;

            Location topLeft = MapInstance.ViewportPointToLocation(new Point(0, 0));

            Point offset = CoordinateTransformation.GeographicToMapPixel(topLeft, GlobalMapPixelWidth);
            OffsetX = offset.X;
            OffsetY = offset.Y;

            if (MapInstance.IsWrapped)
            {
                // If we're zoomed right out, need to offset the offset to account for the 
                // the top left corner of the world being somewhere in the middle of the screen
                ZoomedOutYOffset = CoordinateTransformation.FindYOffset(MapInstance);
                OffsetY -= ZoomedOutYOffset.Y;
            }
        }

        public Point LocationToViewportPoint(Location location)
        {
            var point = CoordinateTransformation.GeographicToMapPixel(location, GlobalMapPixelWidth);

            point.X -= OffsetX;
            point.Y -= OffsetY;

            return point;
        }

        #endregion
    }
}
